﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Modules.FaceScan.Entitys;
using PmSoft;
using PmSoft.Caching.Redis;
using PmSoft.Utilities;
using static Modules.CheckIn.CheckInDetailConstants;

namespace Modules.FaceScan;

/// <summary>
/// 人脸识别业务逻辑类
/// </summary>
[UseDI(ServiceLifetime.Scoped)]
public class FaceScanService
{
    private readonly IConfiguration configuration;
    private readonly PmSoftRedisCache redisCache;
    private const string cacheKeyPrefix = "FaceScanTempRecords";

    public FaceScanService(IConfiguration configuration,
        PmSoftRedisCache redisCache)
    {
        this.configuration = configuration;
        this.redisCache = redisCache;
    }

    /// <summary>
    /// 创建人脸识别
    /// 人脸识别记录暂存到redis，没有没有写到数据库，等待人脸识别后才写入数据库
    /// </summary>
    /// <param name="idCard"></param>
    /// <param name="referType"></param>
    /// <param name="dataSource"></param>
    /// <returns></returns>
    public FaceScanRecord CreateFaceScan(string idCard, FaceScanReferType referType, 数据来源 dataSource)
    {
        int actionCheckCount = configuration.GetValue<int>("FaceActionCheckCount", 4);

        FaceScanRecord record = new()
        {
            ScanCode = Guid.NewGuid().ToString().Replace("-", ""),
            ReferType = referType,
            IdCard = idCard,
            DataSource = dataSource,
            Actions = GetRandFaceActions(actionCheckCount)
        };

        string cacheKey = GetCacheKey(record.ScanCode, referType, dataSource);
        redisCache.Add(cacheKey, record, TimeSpan.FromMinutes(10));

        return record;
    }

    /// <summary>
    /// 校验
    /// </summary>
    /// <param name="idCard"></param>
    /// <param name="scanCode"></param>
    /// <param name="referType"></param>
    /// <param name="dataSource"></param>
    /// <returns></returns>
    public bool Check(string idCard, string scanCode, FaceScanReferType referType, 数据来源 dataSource)
    {
        var record = GetTempScanRecord(scanCode, referType, dataSource);
        if (record == null || record.IdCard != idCard)
            return false;
        //校验后移除记录
        string cacheKey = GetCacheKey(scanCode, referType, dataSource);
        redisCache.Remove(cacheKey);
        return record.IsPassed;
    }

    /// <summary>
    /// 获取扫码记录
    /// </summary>
    /// <param name="scanCode"></param>
    /// <param name="referType"></param>
    /// <param name="dataSource"></param>
    /// <returns></returns>
    public FaceScanRecord? GetTempScanRecord(string scanCode, FaceScanReferType referType, 数据来源 dataSource)
    {
        string cacheKey = GetCacheKey(scanCode, referType, dataSource);
        return redisCache.Get<FaceScanRecord>(cacheKey);
    }

    private string GetCacheKey(string scanCode, FaceScanReferType referType, 数据来源 dataSource)
    {
        return $"{cacheKeyPrefix}:{(int)dataSource}:{referType}:{scanCode}";
    }

    /// <summary>
    /// 获取随机人脸动作
    /// </summary>
    /// <param name="actionCount"></param>
    /// <returns></returns>
    private int[] GetRandFaceActions(int actionCount = 4)
    {
        List<int> selActions;
        var actions = new int[actionCount];
        int lastAction = 0;
        int middleNumber = (int)(actionCount / 2.0);
        for (int i = 0; i < actionCount; i++)
        {
            if (i == middleNumber)//中间插入眨眼
            {
                actions[i] = 5;
                continue;
            }
            selActions = new List<int> { 1, 2, 3, 4 };
            if (lastAction > 0)
                selActions.Remove(lastAction);
            int index = Rand.Next(0, selActions.Count);
            actions[i] = selActions[index];
            lastAction = actions[i];
        }
        return actions;
    }
}
